package com.zhku.search.service.impl;


import com.alibaba.fastjson.JSON;
import com.zhku.base.model.PageParams;
import com.zhku.search.dto.SearchGoodsParamDto;
import com.zhku.search.dto.SearchPageResultDto;
import com.zhku.search.po.GoodsIndex;
import com.zhku.search.service.GoodsSearchService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class GoodsSearchServiceImpl implements GoodsSearchService {

    @Value("${elasticsearch.goods.index}")
    private String goodsIndexStore;

    //source_fields: id,name,grade,mt,st,charge,pic,price,originalPrice,teachmode,validDays,createDate
    @Value("${elasticsearch.goods.source_fields}")
    private String sourceFields;

     @Autowired
     RestHighLevelClient client;

    @Override
    public SearchPageResultDto<GoodsIndex> queryGoodsPubIndex(PageParams pageParams, SearchGoodsParamDto goodsSearchParam) {

        //创建搜索请求对象
        SearchRequest searchRequest = new SearchRequest(goodsIndexStore);

        //搜索源构建器，用于构建搜索的查询条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //创建布尔查询构建器，用于组合多个查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //source源字段过虑
        String[] sourceFieldsArray = sourceFields.split(",");
        //设置源字段过滤，只返回指定的字段（source_fields: id,name,grade,mt,
        // st,charge,pic,price,originalPrice,teachmode,validDays,createDate
        searchSourceBuilder.fetchSource(sourceFieldsArray, new String[]{});
        //判断分页参数是否为空，为空则自己创建一个
        if(goodsSearchParam==null){
            goodsSearchParam = new SearchGoodsParamDto();
        }
        //判断课程搜索条件中的关键字是否为空
        if(StringUtils.isNotEmpty(goodsSearchParam.getKeywords())){
            //不为空，创建一个多字段匹配查询构建器 multiMatchQueryBuilder
            //匹配关键字
            //multiMatchQueryBuilder 是用来构建搜索关键字的匹配条件
            //设置当用户输入关键字时，主要在name和description字段中搜索
            MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(goodsSearchParam.getKeywords(), "goodsName", "goodsIntro");
            //设置匹配占比
            multiMatchQueryBuilder.minimumShouldMatch("70%");
            //提升另个字段的Boost值
            multiMatchQueryBuilder.field("goodsName",10);
            boolQueryBuilder.must(multiMatchQueryBuilder);
        }

        //分页
        Long pageNo = pageParams.getPageNo();
        Long pageSize = pageParams.getPageSize();
        int start = (int) ((pageNo-1)*pageSize);
        //设置搜索结果的起始位置
        searchSourceBuilder.from(start);
        //设置每页的返回数
        searchSourceBuilder.size(Math.toIntExact(pageSize));
        //布尔查询
        searchSourceBuilder.query(boolQueryBuilder);
        //高亮设置
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.preTags("<font class='eslight'>");
        highlightBuilder.postTags("</font>");
        //设置高亮字段
        highlightBuilder.fields().add(new HighlightBuilder.Field("goodsName"));
        searchSourceBuilder.highlighter(highlightBuilder);
        //请求搜索
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = null;
        try {
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("商品搜索异常：{}",e.getMessage());
            return new SearchPageResultDto<GoodsIndex>(new ArrayList(),0,0,0);
        }

        //结果集处理
        SearchHits hits = searchResponse.getHits();
        SearchHit[] searchHits = hits.getHits();
        //记录总数
        TotalHits totalHits = hits.getTotalHits();
        //数据列表
        List<GoodsIndex> list = new ArrayList<>();

        for (SearchHit hit : searchHits) {

            String sourceAsString = hit.getSourceAsString();
            GoodsIndex goodsIndex = JSON.parseObject(sourceAsString, GoodsIndex.class);

            //取出source
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();

            //课程id
            String id = goodsIndex.getId();
            //取出名称
            String name = goodsIndex.getGoodsName();
            //取出高亮字段内容
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if(highlightFields!=null){
                HighlightField nameField = highlightFields.get("goodsNname");
                if(nameField!=null){
                    Text[] fragments = nameField.getFragments();
                    StringBuffer stringBuffer = new StringBuffer();
                    for (Text str : fragments) {
                        stringBuffer.append(str.string());
                    }
                    name = stringBuffer.toString();

                }
            }
            goodsIndex.setId(id);
            goodsIndex.setGoodsName(name);

            list.add(goodsIndex);

        }
        SearchPageResultDto<GoodsIndex> pageResult = new SearchPageResultDto<>(list, totalHits.value,pageNo,pageSize);

        return pageResult;
    }

}
